#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
彩票定时任务调度器 - 修复版本
根据各彩种的开奖时间自动执行数据获取和更新任务
"""

import schedule
import time
import sys
import os
from datetime import datetime, timedelta
from typing import Dict, List
from loguru import logger
import threading
import subprocess
import signal
from dotenv import load_dotenv

# 加载 .env 文件
env_path = os.path.join(os.path.dirname(__file__), '.env')
load_dotenv(env_path)

# 添加项目根目录到Python路径
root_path = os.getenv('ROOT_PATH', '')
if root_path:
    sys.path.append(root_path)
    print(f"✅ 已加载项目根目录: {root_path}")
else:
    print("⚠️ 未找到ROOT_PATH环境变量")



from crawler.spiders.jisu_spider import JisuLotterySpider
from crawler.config.settings import LOTTERY_TYPES

class LotteryScheduler:
    """彩票定时任务调度器"""
    
    def __init__(self):
        self.running = True
        self.tasks = {}
        self.setup_logging()
        self.setup_signal_handlers()
        
    def setup_logging(self):
        """设置日志"""
        logger.remove()
        logger.add(
            "logs/lottery_scheduler.log",
            rotation="1 day",
            retention="30 days",
            level="INFO",
            format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}"
        )
        logger.add(sys.stdout, level="INFO")
        
    def setup_signal_handlers(self):
        """设置信号处理器"""
        signal.signal(signal.SIGINT, self.signal_handler)
        signal.signal(signal.SIGTERM, self.signal_handler)
        
    def signal_handler(self, signum, frame):
        """信号处理器"""
        logger.info(f"接收到信号 {signum}，正在停止调度器...")
        self.running = False
        
    def fetch_lottery_results(self, lottery_type: str):
        """获取开奖结果（第一次执行）"""
        try:
            logger.info(f"🎯 开始获取 {LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)} 开奖结果")
            
            spider = JisuLotterySpider(lottery_type)
            # 获取最新一期数据
            saved_count = spider.crawl_latest(count=1)
            
            if saved_count > 0:
                logger.success(f"✅ {LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)} 开奖结果获取成功，保存 {saved_count} 条数据")
            else:
                logger.warning(f"⚠️ {LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)} 开奖结果获取失败或无新数据")
                
        except Exception as e:
            logger.error(f"❌ 获取 {lottery_type} 开奖结果失败: {e}")
            
    def update_prize_info(self, lottery_type: str):
        """更新各奖项中奖情况（第二次执行）"""
        try:
            logger.info(f"🔄 开始更新 {LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)} 各奖项中奖情况")
            
            spider = JisuLotterySpider(lottery_type)
            # 再次获取最新数据（此时API可能已包含奖级信息）
            saved_count = spider.crawl_latest(count=1)
            
            if saved_count > 0:
                logger.success(f"✅ {LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)} 奖项信息更新成功")
            else:
                logger.warning(f"⚠️ {LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)} 奖项信息更新失败或无变化")
                
        except Exception as e:
            logger.error(f"❌ 更新 {lottery_type} 奖项信息失败: {e}")
            
    def fetch_official_prize_data(self, lottery_type: str):
        """抓取官网一等奖中奖数据"""
        try:
            lottery_name = LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)
            logger.info(f"🏆 开始抓取 {lottery_name} 官网一等奖中奖数据")
            
            # 根据彩种调用不同的官网抓取逻辑
            if lottery_type == "kl8":
                # 快乐8 - 抓取选十中十中奖情况
                result = self._crawl_kl8_official_data()
            elif lottery_type in ["ssq"]:
                # 双色球 - 抓取福利彩票官网一等奖数据
                result = self._crawl_welfare_lottery_data(lottery_type)
            elif lottery_type in ["dlt", "qxc"]:
                # 大乐透、七星彩 - 抓取体育彩票官网一等奖数据
                result = self._crawl_sports_lottery_data(lottery_type)
            elif lottery_type == "qlc":
                # 七乐彩 - 抓取福利彩票官网一等奖数据
                result = self._crawl_welfare_lottery_data(lottery_type)
            else:
                logger.warning(f"⚠️ 暂不支持 {lottery_type} 的官网数据抓取")
                return
                
            if result and result.get('success'):
                logger.success(f"✅ {lottery_name} 官网一等奖数据抓取成功")
            else:
                logger.warning(f"⚠️ {lottery_name} 官网一等奖数据抓取失败或无新数据")
                
        except Exception as e:
            logger.error(f"❌ 抓取 {lottery_type} 官网一等奖数据失败: {e}")
    
    def _crawl_kl8_official_data(self):
        """抓取快乐8选十中十官网数据"""
        try:
            import requests
            import json
            
            logger.info("🎯 抓取快乐8选十中十中奖情况...")
            
            # 快乐8API接口地址
            api_url = "https://www.cwl.gov.cn/cwl_admin/front/cwlkj/search/kjxx/findDrawNotice"
            
            # API参数
            params = {
                'name': 'kl8',
                'issueCount': '',
                'issueStart': '',
                'issueEnd': '',
                'dayStart': '',
                'dayEnd': '',
                'pageNo': 1,
                'pageSize': 30,
                'week': '',
                'systemType': 'PC'
            }
            
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                'Accept': 'application/json, text/plain, */*',
                'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
                'Accept-Encoding': 'gzip, deflate, br',
                'Connection': 'keep-alive',
                'Referer': 'https://www.cwl.gov.cn/',
                'Sec-Fetch-Dest': 'empty',
                'Sec-Fetch-Mode': 'cors',
                'Sec-Fetch-Site': 'same-origin',
                'X-Requested-With': 'XMLHttpRequest',
            }
            
            session = requests.Session()
            session.headers.update(headers)
            
            logger.info(f"访问快乐8API接口: {api_url}")
            response = session.get(api_url, params=params, timeout=30)
            response.raise_for_status()
            
            # 解析JSON响应
            json_data = response.json()
            
            if json_data.get('result'):
                result_list = json_data['result']
                if result_list:
                    result_list[0]['lottery_type'] = 'kl8'
                    saved_count = self._save_kl8_province_data(result_list)
                    logger.success(f"✅ 快乐8选十中十中奖数据抓取成功，期号: {result_list[0]['code']}")
                    return {"success": True, "count": saved_count, "period": result_list[0]['code']}
                  
                else:
                    logger.warning("⚠️ 快乐8API返回空结果，不生成模拟数据")
                    return {"success": False, "count": 0, "message": "API返回空结果"}
            else:
                logger.warning(f"⚠️ 快乐8API调用失败: {json_data}")
                return {"success": False, "count": 0, "message": "API调用失败"}
                
        except requests.RequestException as e:
            logger.error(f"快乐8API访问失败: {e}")
            return {"success": False, "error": f"网络请求失败: {str(e)}"}
        except json.JSONDecodeError as e:
            logger.error(f"快乐8API响应解析失败: {e}")
            return {"success": False, "error": f"JSON解析失败: {str(e)}"}
        except Exception as e:
            logger.error(f"快乐8API数据抓取失败: {e}")
            return {"success": False, "error": str(e)}
    

    def _save_kl8_province_data(self, prize_details):
        """保存快乐8省份中奖数据到lottery_results表的province_prizes字段"""
        try:
            from crawler.database import db_manager
            
            if not prize_details:
                return 0
            
            period = prize_details[0]['code']
            lottery_type = prize_details[0]['lottery_type']
            
            # 构建province_prizes字符串
            
            province_prizes_str =  prize_details[0]['content']
            
            # 更新lottery_results表的province_prizes字段
            update_sql = """
                UPDATE lottery_results 
                SET province_prizes = %s, updated_at = CURRENT_TIMESTAMP
                WHERE lottery_type = %s AND period = %s
            """
            
            params = (province_prizes_str, lottery_type, period)
            
            try:
                db_manager.execute_query(update_sql, params)
                logger.info(f"快乐8选十中十省份数据已保存到lottery_results: 期号{period}, province_prizes='{province_prizes_str}'")
                return 1
            except Exception as e:
                logger.error(f"更新快乐8省份数据失败: {e}")
                return 0
                
        except Exception as e:
            logger.error(f"保存快乐8省份数据到lottery_results失败: {e}")
            return 0
    
    
    
    
    
    def _crawl_welfare_lottery_data(self, lottery_type: str):
        """抓取福利彩票官网一等奖数据（双色球、七乐彩）"""
        try:
            lottery_name = LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)
            logger.info(f"🎯 抓取{lottery_name}福利彩票官网一等奖数据...")
            
            if lottery_type == "ssq":
                # 双色球使用API接口
                return self._crawl_ssq_api_data()
            elif lottery_type == "qlc":
                # 七乐彩使用API接口
                return self._crawl_qlc_api_data()
            else:
                logger.error(f"不支持的福彩彩种: {lottery_type}")
                return {"success": False, "error": f"不支持的彩种: {lottery_type}"}
                
        except Exception as e:
            logger.error(f"{lottery_type}福彩官网数据抓取失败: {e}")
            return {"success": False, "error": str(e)}
    
    def _crawl_ssq_api_data(self):
        """抓取双色球API接口数据"""
        try:
            import requests
            import json
            
            # 双色球API接口地址
            api_url = "https://www.cwl.gov.cn/cwl_admin/front/cwlkj/search/kjxx/findDrawNotice"
            
            # API参数
            params = {
                'name': 'ssq',
                'issueCount': '',
                'issueStart': '',
                'issueEnd': '',
                'dayStart': '',
                'dayEnd': '',
                'pageNo': 1,
                'pageSize': 30,
                'week': '',
                'systemType': 'PC'
            }
            
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                'Accept': 'application/json, text/plain, */*',
                'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
                'Accept-Encoding': 'gzip, deflate, br',
                'Connection': 'keep-alive',
                'Referer': 'https://www.cwl.gov.cn/',
                'Sec-Fetch-Dest': 'empty',
                'Sec-Fetch-Mode': 'cors',
                'Sec-Fetch-Site': 'same-origin',
                'X-Requested-With': 'XMLHttpRequest',
            }
            
            session = requests.Session()
            session.headers.update(headers)
            
            logger.info(f"访问双色球API接口: {api_url}")
            response = session.get(api_url, params=params, timeout=30)
            response.raise_for_status()
            
            # 解析JSON响应
            json_data = response.json()
            
            if json_data.get('result'):
                result_list = json_data['result']
                if result_list:
                    # print(result_list[0])
                    # exit(0);
                    result_list[0]['lottery_type'] = 'ssq'
                    saved_count = self._save_ssq_province_data(result_list)
                    logger.success(f"✅ 双色球一等奖中奖数据抓取成功，期号: {result_list[0]['code']}")
                    return {"success": True, "count": saved_count, "period": result_list[0]['code']}
                else:
                    logger.warning("⚠️ 双色球API返回空结果，不生成模拟数据")
                    return {"success": False, "count": 0, "message": "API返回空结果"}
            else:
                logger.warning(f"⚠️ 双色球API调用失败: {json_data}")
                return {"success": False, "count": 0, "message": "API调用失败"}
                
        except requests.RequestException as e:
            logger.error(f"双色球API访问失败: {e}")
            return {"success": False, "error": f"网络请求失败: {str(e)}"}
        except json.JSONDecodeError as e:
            logger.error(f"双色球API响应解析失败: {e}")
            return {"success": False, "error": f"JSON解析失败: {str(e)}"}
        except Exception as e:
            logger.error(f"双色球API数据抓取失败: {e}")
            return {"success": False, "error": str(e)}
  
    def _save_ssq_province_data(self, prize_details):
        """保存双色球省份中奖数据到lottery_results表的province_prizes字段"""
        try:
            from crawler.database import db_manager
            
            if not prize_details:
                return 0
            
            period = prize_details[0]['code']
            lottery_type = prize_details[0]['lottery_type']
            
            # 更新lottery_results表的province_prizes字段
            province_prizes_str = prize_details[0]['content']

         
            update_sql = """
                UPDATE lottery_results 
                SET province_prizes = %s, updated_at = CURRENT_TIMESTAMP
                WHERE lottery_type = %s AND period = %s
            """
            
            params = (province_prizes_str, lottery_type, period)
            
            try:
                db_manager.execute_query(update_sql, params)
                logger.info(f"双色球一等奖省份数据已保存到lottery_results: 期号{period}, province_prizes='{province_prizes_str}'")
                return 1
            except Exception as e:
                logger.error(f"更新双色球省份数据失败: {e}")
                return 0
                
        except Exception as e:
            logger.error(f"保存双色球省份数据到lottery_results失败: {e}")
            return 0
    
    def _crawl_qlc_api_data(self):
        """抓取七乐彩API接口数据"""
        try:
            import requests
            import json
            
            # 七乐彩一等奖中奖接口地址
            api_url = "https://www.cwl.gov.cn/cwl_admin/front/cwlkj/search/kjxx/findDrawNotice"
            
            # API参数
            params = {
                'name': 'qlc',
                'issueCount': '',
                'issueStart': '',
                'issueEnd': '',
                'dayStart': '',
                'dayEnd': '',
                'pageNo': 1,
                'pageSize': 30,
                'week': '',
                'systemType': 'PC'
            }
            
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                'Accept': 'application/json, text/plain, */*',
                'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
                'Accept-Encoding': 'gzip, deflate, br',
                'Connection': 'keep-alive',
                'Referer': 'https://www.cwl.gov.cn/',
                'Sec-Fetch-Dest': 'empty',
                'Sec-Fetch-Mode': 'cors',
                'Sec-Fetch-Site': 'same-origin',
                'X-Requested-With': 'XMLHttpRequest',
            }
            
            session = requests.Session()
            session.headers.update(headers)
            
            logger.info(f"访问七乐彩API接口: {api_url}")
            response = session.get(api_url, params=params, timeout=30)
            response.raise_for_status()
            
            # 解析JSON响应
            json_data = response.json()
            
            if json_data.get('result'):
                result_list = json_data['result']
                if result_list:
                    result_list[0]['lottery_type'] = 'qlc'
                    saved_count = self._save_qlc_province_data(result_list)
                    logger.success(f"✅ 七乐彩一等奖中奖数据抓取成功，期号: {result_list[0]['code']}")
                    return {"success": True, "count": saved_count, "period": result_list[0]['code']}
                else:
                    logger.warning("⚠️ 七乐彩API返回空结果，不生成模拟数据")
                    return {"success": False, "count": 0, "message": "API返回空结果"}
            else:
                logger.warning(f"⚠️ 七乐彩API调用失败: {json_data}")
                return {"success": False, "count": 0, "message": "API调用失败"}
                
        except requests.RequestException as e:
            logger.error(f"七乐彩API访问失败: {e}")
            return {"success": False, "error": f"网络请求失败: {str(e)}"}
        except json.JSONDecodeError as e:
            logger.error(f"七乐彩API响应解析失败: {e}")
            return {"success": False, "error": f"JSON解析失败: {str(e)}"}
        except Exception as e:
            logger.error(f"七乐彩API数据抓取失败: {e}")
            return {"success": False, "error": str(e)}
    
   
    def _save_qlc_province_data(self, prize_details):
        """保存七乐彩省份中奖数据到lottery_results表的province_prizes字段"""
        try:
            from crawler.database import db_manager
            
            if not prize_details:
                return 0
            
            period = prize_details[0]['code']
            lottery_type = prize_details[0]['lottery_type']
            
            # 构建province_prizes字符串
            province_prizes_str = prize_details[0]['content']
            
            # 更新lottery_results表的province_prizes字段
            update_sql = """
                UPDATE lottery_results 
                SET province_prizes = %s, updated_at = CURRENT_TIMESTAMP
                WHERE lottery_type = %s AND period = %s
            """
            params = (province_prizes_str, lottery_type, period)
            try:
                db_manager.execute_query(update_sql, params)
                logger.info(f"七乐彩一等奖省份数据已保存到lottery_results: 期号{period}, province_prizes='{province_prizes_str}'")
                return 1
            except Exception as e:
                logger.error(f"更新七乐彩省份数据失败: {e}")
                return 0
                
        except Exception as e:
            logger.error(f"保存七乐彩省份数据到lottery_results失败: {e}")
            return 0
    
    def _get_latest_period(self, lottery_type: str):
        """获取最新期号"""
        try:
            from crawler.database import db_manager
            
            # 从数据库获取最新期号
            result = db_manager.get_latest_period(lottery_type)
            
            if result:
                return result
            else:
                # 如果数据库中没有数据，生成一个默认期号
                today = datetime.now()
                if lottery_type == "ssq":
                    # 双色球一周三期，期号格式：2024001
                    year = today.year
                    # 简单估算当前期号
                    week_of_year = today.isocalendar()[1]
                    period_num = week_of_year * 3
                    return f"{year}{period_num:03d}"
                elif lottery_type == "qlc":
                    # 七乐彩一周三期，期号格式：2024001
                    year = today.year
                    week_of_year = today.isocalendar()[1]
                    period_num = week_of_year * 3
                    return f"{year}{period_num:03d}"
                
        except Exception as e:
            logger.error(f"获取最新期号失败: {e}")
            # 返回默认期号
            today = datetime.now()
            return f"{today.year}001"
    
    
    
    
    def _crawl_sports_lottery_data(self, lottery_type: str):
        """抓取体育彩票官网一等奖数据（大乐透、七星彩）"""
        try:
            lottery_name = LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)
            logger.info(f"🎯 抓取{lottery_name}体育彩票官网一等奖数据...")
            
            # 获取最新期号
            latest_period = self._get_latest_period(lottery_type)
            if not latest_period:
                logger.warning(f"无法获取{lottery_name}最新期号")
                return {"success": False, "count": 0, "message": "无法获取最新期号"}
            
            # 体彩官网PDF文件解析
            if lottery_type == "dlt":
                # 大乐透彩票类型：33800
                return self._crawl_sports_pdf_data(lottery_type, latest_period, "33800")
            elif lottery_type == "qxc":
                # 七星彩彩票类型：17100
                return self._crawl_sports_pdf_data(lottery_type, latest_period, "17100")
            else:
                logger.error(f"不支持的体彩彩种: {lottery_type}")
                return {"success": False, "error": f"不支持的彩种: {lottery_type}"}
                
        except Exception as e:
            logger.error(f"{lottery_type}体彩官网数据抓取失败: {e}")
            return {"success": False, "error": str(e)}
    
    def _crawl_sports_pdf_data(self, lottery_type, period, lottery_code):
        """抓取体彩PDF文件数据"""
        try:
            import requests
            import pdfplumber
            import io
            
            lottery_name = LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)
            
            # 构建PDF文件URL
            # PDF地址格式：域名地址+彩票类型+当前期号+文件名
            pdf_url = f"https://pdf.sporttery.cn/{lottery_code}/{period}/{period}.pdf"
            
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                'Accept': 'application/pdf,*/*',
                'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
                'Accept-Encoding': 'gzip, deflate, br',
                'Connection': 'keep-alive',
                'Referer': 'https://www.lottery.gov.cn/',
            }
            
            session = requests.Session()
            session.headers.update(headers)
            
           
            response = session.get(pdf_url, timeout=60)
            response.raise_for_status()
            
            # 检查响应是否为PDF
            content_type = response.headers.get('content-type', '').lower()
            if 'pdf' not in content_type and len(response.content) < 1000:
                logger.warning(f"PDF文件无效: {content_type}")
                return {"success": False, "count": 0, "message": "PDF文件无效"}
            
            logger.info(f"PDF文件读取成功，大小: {len(response.content)} bytes")
            
            # 直接从内存解析PDF内容，无需创建临时文件
            province_prizes_str = self._parse_sports_pdf_content_from_bytes(response.content)
         
            prize_details = [{'province_prizes':province_prizes_str,'period':period,'lottery_type':lottery_type}]
            if province_prizes_str:
                # 保存到数据库
                saved_count = self._save_sports_province_data(prize_details)
                logger.success(f"✅ {lottery_name}PDF数据抓取成功，期号: {period}")
                return {"success": True, "count": saved_count, "period": period}
            else:
                logger.warning(f"⚠️ 未从{lottery_name}PDF中解析到一等奖数据，不生成模拟数据")
                return {"success": False, "count": 0, "message": "PDF解析失败"}
                
        except requests.RequestException as e:
            logger.error(f"{lottery_type}PDF读取失败: {e}")
            return {"success": False, "error": f"PDF读取失败: {str(e)}"}
        except Exception as e:
            logger.error(f"{lottery_type}PDF数据抓取失败: {e}")
            return {"success": False, "error": str(e)}
    
    def _parse_sports_pdf_content_from_bytes(self, pdf_bytes):
        """从字节流在线解析体彩PDF文件内容（无需创建临时文件）"""
        try:
            import pdfplumber
            import io
            import re
            
            # 使用BytesIO从内存中直接解析PDF
            with pdfplumber.open(io.BytesIO(pdf_bytes)) as pdf:
                # 提取所有页面的文本
                full_text = ""
                for page in pdf.pages:
                    page_text = page.extract_text()
                    if page_text:
                        full_text += page_text + "\n"
                
                logger.info(f"在线PDF文本提取完成，总长度: {len(full_text)} 字符")
                
                if not full_text.strip():
                    logger.warning("PDF文本提取为空")
                    return None
                
                # 优先查找完整的省份中奖明细
                province_prize_info = self._extract_province_details_from_pdf(full_text)
                if province_prize_info:
                    return province_prize_info
                
                # 如果没有找到详细省份信息，查找简单的一等奖信息
                patterns = [
                    r'本期一等奖出自[：:\s]*([^\n]+)',
                    r'一等奖[：:\s]*([^二三四五六七八九\n]+)',
                    r'基本投注一等奖[：:\s]*([^二三四五六七八九\n]+)',
                    r'一等奖.*?([^二三四五六七八九\n]+注)',
                ]
                
                first_prize_content = None
                for pattern in patterns:
                    match = re.search(pattern, full_text, re.MULTILINE | re.DOTALL)
                    if match:
                        first_prize_content = match.group(1)
                        logger.info(f"找到一等奖内容: {first_prize_content}...")
                        break
                
                if first_prize_content:
                    return first_prize_content

                logger.warning("未从PDF中解析到有效的一等奖数据")
                # 记录部分PDF内容用于调试
                logger.debug(f"PDF内容片段: {full_text[:500]}...")
                return None
             
        except Exception as e:
            logger.error(f"在线解析PDF文件失败: {e}")
            return None
    
    def _parse_sports_pdf_content(self, pdf_path):
        """解析体彩PDF文件内容（兼容旧版本，保留文件路径解析方法）"""
        try:
            import pdfplumber
            import re
            
            with pdfplumber.open(pdf_path) as pdf:
                # 提取所有页面的文本
                full_text = ""
                for page in pdf.pages:
                    page_text = page.extract_text()
                    if page_text:
                        full_text += page_text + "\n"
                
                logger.info(f"PDF文本提取完成，总长度: {len(full_text)} 字符")
                
                if not full_text.strip():
                    logger.warning("PDF文本提取为空")
                    return None
                
                # 优先查找完整的省份中奖明细
                province_prize_info = self._extract_province_details_from_pdf(full_text)
                if province_prize_info:
                    return province_prize_info
                
                # 如果没有找到详细省份信息，查找简单的一等奖信息
                patterns = [
                    r'本期一等奖出自[：:\s]*([^\n]+)',
                    r'一等奖[：:\s]*([^二三四五六七八九\n]+)',
                    r'基本投注一等奖[：:\s]*([^二三四五六七八九\n]+)',
                    r'一等奖.*?([^二三四五六七八九\n]+注)',
                ]
                
                first_prize_content = None
                for pattern in patterns:
                    match = re.search(pattern, full_text, re.MULTILINE | re.DOTALL)
                    if match:
                        first_prize_content = match.group(1)
                        logger.info(f"找到一等奖内容: {first_prize_content}...")
                        break
                
                if first_prize_content:
                    return first_prize_content

                logger.warning("未从PDF中解析到有效的一等奖数据")
                # 记录部分PDF内容用于调试
                logger.debug(f"PDF内容片段: {full_text[:500]}...")
                return None
             
        except Exception as e:
            logger.error(f"解析PDF文件失败: {e}")
            return None
    
    def _extract_province_details_from_pdf(self, full_text):
        """从PDF文本中提取省份详细中奖信息"""
        try:
            import re
            
            # 查找省份中奖明细部分
            # 寻找包含省份名称和中奖注数的模式
            province_patterns = [
                # 匹配 "河北（基本1注）、内蒙古（基本2注 追加2注）" 等格式
                r'([^（）、，\s]+)（([^（）]+)）',
                # 匹配 "河北 基本1注、内蒙古 基本2注 追加2注" 等格式  
                r'([^（）、，\s]+)\s*(基本\d+注[^、，\n]*)',
                # 匹配 "河北（基本1 注）" 格式（注意空格）
                r'([^（）、，\s]+)（([^（）\n]+)）',
                # 匹配简单的 "河北1注、上海2注" 格式
                r'([^（）、，\s\d]+)(\d+注)',
            ]
            
            province_details = []
            
            # 尝试不同的匹配模式
            for pattern in province_patterns:
                matches = re.findall(pattern, full_text)
                if matches:
                    logger.info(f"使用模式 '{pattern}' 找到 {len(matches)} 个省份匹配")
                    
                    for match in matches:
                        province_name = match[0].strip()
                        prize_info = match[1].strip()
                        
                        # 验证省份名称是否合理
                        if self._is_valid_province_name(province_name):
                            # 解析注数信息
                            note_info = self._parse_prize_notes(prize_info)
                            if note_info:
                                # 清理格式，移除多余的括号
                                clean_note_info = note_info.replace("（", "").replace("）", "")
                                province_details.append(f"{province_name}（{clean_note_info}）")
                                logger.debug(f"解析省份: {province_name} -> {clean_note_info}")
                    
                    if province_details:
                        break
            
            # 如果找到了省份详细信息，格式化返回
            if province_details:
                result = "、".join(province_details) + "。"
                logger.info(f"成功解析到 {len(province_details)} 个省份的详细中奖信息")
                return result
            
            # 如果没有找到详细的省份信息，尝试查找简化的省份列表
            simplified_patterns = [
                # 查找 "本期一等奖出自：河北、内蒙古、黑龙江..." 格式
                r'本期一等奖出自[：:\s]*([^。\n]+)',
                # 查找表格中的省份信息
                r'一等奖.*?出自[：:\s]*([^。\n]+)',
            ]
            
            for pattern in simplified_patterns:
                match = re.search(pattern, full_text, re.MULTILINE)
                if match:
                    province_text = match.group(1).strip()
                    # 简单清理和格式化
                    if province_text and len(province_text) > 2:
                        logger.info(f"找到简化的省份信息: {province_text}")
                        return province_text + "。"
            
            return None
            
        except Exception as e:
            logger.error(f"提取省份详细信息失败: {e}")
            return None
    
    def _is_valid_province_name(self, name):
        """验证是否为有效的省份名称"""
        if not name or len(name) < 2:
            return False
        
        # 中国省份/直辖市/自治区列表
        valid_provinces = [
            '北京', '天津', '河北', '山西', '内蒙古', '内蒙',
            '辽宁', '吉林', '黑龙江',
            '上海', '江苏', '浙江', '安徽', '福建', '江西', '山东',
            '河南', '湖北', '湖南', '广东', '广西', '海南',
            '重庆', '四川', '贵州', '云南', '西藏',
            '陕西', '甘肃', '青海', '宁夏', '新疆'
        ]
        
        # 检查是否包含有效省份名称
        for province in valid_provinces:
            if province in name:
                return True
        
        return False
    
    def _parse_prize_notes(self, prize_info):
        """解析中奖注数信息"""
        try:
            import re
            
            if not prize_info:
                return None
            
            # 如果已经是注数格式，直接返回
            if '注' in prize_info:
                return prize_info
            
            # 尝试从文本中提取注数
            note_patterns = [
                r'基本(\d+)注',
                r'追加(\d+)注',
                r'(\d+)注',
            ]
            
            notes = []
            for pattern in note_patterns:
                matches = re.findall(pattern, prize_info)
                for match in matches:
                    if 'basic' not in pattern and 'additional' not in pattern:
                        notes.append(f"{match}注")
                    elif 'basic' in pattern:
                        notes.append(f"基本{match}注")
                    elif 'additional' in pattern:
                        notes.append(f"追加{match}注")
            
            if notes:
                return " ".join(notes)
            
            return prize_info
            
        except Exception as e:
            logger.error(f"解析注数信息失败: {e}")
            return prize_info
    
    def _save_sports_province_data(self, prize_details):
        """保存体彩省份中奖数据到lottery_results表的province_prizes字段"""
        try:
            from crawler.database import db_manager
            
            if not prize_details:
                return 0
            
            period = prize_details[0]['period']
            lottery_type = prize_details[0]['lottery_type']
            lottery_name = LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)
            
            # 构建province_prizes字符串
            province_prizes_str = prize_details[0]['province_prizes']
            
            # 清理格式问题
            if province_prizes_str:
                # 移除多余的前缀文本
                if "本期一等奖出自：" in province_prizes_str:
                    province_prizes_str = province_prizes_str.replace("本期一等奖出自：", "")
                # 清理多余的括号和格式问题
                province_prizes_str = province_prizes_str.replace("(（", "（").replace("）)", "）")
                province_prizes_str = province_prizes_str.replace(")）", "）").replace("（)", "（")
                province_prizes_str = province_prizes_str.replace("注)", "注").replace("注 )", "注")
                # 清理多余空格
                province_prizes_str = province_prizes_str.replace("注 ）", "注）").replace("） 、", "）、")
            
            # 更新lottery_results表的province_prizes字段
            update_sql = """
                UPDATE lottery_results 
                SET province_prizes = %s, updated_at = CURRENT_TIMESTAMP
                WHERE lottery_type = %s AND period = %s
            """
            
            params = (province_prizes_str, lottery_type, period)
            
            try:
                db_manager.execute_query(update_sql, params)
                logger.info(f"{lottery_name}一等奖省份数据已保存到lottery_results: 期号{period}, province_prizes='{province_prizes_str}'")
                return 1
            except Exception as e:
                logger.error(f"更新{lottery_name}省份数据失败: {e}")
                return 0
                
        except Exception as e:
            logger.error(f"保存{lottery_type}省份数据到lottery_results失败: {e}")
            return 0
    
    def _parse_sports_prize_data(self, soup, lottery_type: str, period: str):
        """解析体彩一等奖数据"""
        try:
            import re
            
            # 查找包含一等奖信息的表格或区域
            prize_tables = soup.find_all('table', class_=['prize-table', 'result-table', 'data-table', 'kj-table'])
            
            for table in prize_tables:
                rows = table.find_all('tr')
                for row in rows:
                    cells = row.find_all(['td', 'th'])
                    if len(cells) >= 3:
                        prize_name = cells[0].get_text(strip=True)
                        if '一等奖' in prize_name:
                            winners = self._extract_number(cells[1].get_text(strip=True))
                            amount = self._extract_amount(cells[2].get_text(strip=True))
                            
                            return {
                                'lottery_type': lottery_type,
                                'period': period,
                                'prize_name': '一等奖',
                                'winners': winners,
                                'single_amount': amount,
                                'total_amount': winners * amount if winners and amount else 0
                            }
            
            # 如果没有找到表格，尝试从文本内容中解析
            content_areas = soup.find_all(['div', 'p'], class_=['content', 'main-content', 'article-content', 'prize-info', 'kj-content'])
            
            for area in content_areas:
                text = area.get_text()
                
                # 匹配一等奖信息的正则表达式
                patterns = [
                    r'一等奖.*?(\d+).*?注.*?(\d+(?:,\d+)*(?:\.\d+)?).*?元',
                    r'一等奖.*?(\d+).*?注.*?单注奖金.*?(\d+(?:,\d+)*(?:\.\d+)?).*?元',
                    r'基本投注一等奖.*?(\d+).*?注.*?(\d+(?:,\d+)*(?:\.\d+)?).*?元'
                ]
                
                for pattern in patterns:
                    match = re.search(pattern, text)
                    if match:
                        winners = int(match.group(1))
                        # 处理包含逗号的金额
                        amount_str = match.group(2).replace(',', '')
                        amount = float(amount_str)
                        
                        return {
                            'lottery_type': lottery_type,
                            'period': period,
                            'prize_name': '一等奖',
                            'winners': winners,
                            'single_amount': amount,
                            'total_amount': winners * amount
                        }
            
            # 尝试查找更具体的体彩页面结构
            prize_divs = soup.find_all('div', class_=['prize-item', 'prize-level', 'level-1'])
            for div in prize_divs:
                text = div.get_text()
                if '一等奖' in text:
                    # 提取数字信息
                    numbers = re.findall(r'\d+(?:,\d+)*(?:\.\d+)?', text)
                    if len(numbers) >= 2:
                        winners = int(numbers[0].replace(',', ''))
                        amount = float(numbers[1].replace(',', ''))
                        
                        return {
                            'lottery_type': lottery_type,
                            'period': period,
                            'prize_name': '一等奖',
                            'winners': winners,
                            'single_amount': amount,
                            'total_amount': winners * amount
                        }
            
            return None
            
        except Exception as e:
            logger.error(f"解析{lottery_type}体彩数据失败: {e}")
            return None
    
    def _generate_mock_sports_data(self, lottery_type, period):
        """生成体彩模拟数据（用于测试）"""
        import random
        
        # 根据彩种生成不同的模拟数据
        if lottery_type == "dlt":
            # 大乐透一等奖
            winners = random.randint(2, 30)
            single_amount = random.randint(8000000, 15000000)  # 800万-1500万
        elif lottery_type == "qxc":
            # 七星彩一等奖
            winners = random.randint(1, 15)
            single_amount = random.randint(3000000, 8000000)   # 300万-800万
        else:
            winners = random.randint(1, 10)
            single_amount = random.randint(1000000, 5000000)
        
        lottery_name = LOTTERY_TYPES.get(lottery_type, {}).get('name', lottery_type)
        logger.info(f"生成{lottery_name}模拟数据: 期号{period}, 一等奖中奖{winners}注, 单注奖金{single_amount}元")
        
        return {
            'lottery_type': lottery_type,
            'period': period,
            'prize_name': '一等奖',
            'winners': winners,
            'single_amount': single_amount,
            'total_amount': winners * single_amount
        }
    
    def _save_sports_prize_data(self, prize_data):
        """保存体彩一等奖数据到数据库"""
        try:
            from crawler.database import db_manager
            
            # 插入或更新lottery_prize_details表
            insert_sql = """
                INSERT INTO lottery_prize_details 
                (lottery_type, period, total_first_prize_winners, total_first_prize_amount)
                VALUES (%s, %s, %s, %s)
                ON DUPLICATE KEY UPDATE
                total_first_prize_winners = VALUES(total_first_prize_winners),
                total_first_prize_amount = VALUES(total_first_prize_amount),
                updated_at = CURRENT_TIMESTAMP
            """
            
            params = (
                prize_data['lottery_type'],
                prize_data['period'],
                prize_data['winners'],
                prize_data['total_amount']
            )
            
            try:
                db_manager.execute_query(insert_sql, params)
                lottery_name = LOTTERY_TYPES.get(prize_data['lottery_type'], {}).get('name', prize_data['lottery_type'])
                logger.info(f"{lottery_name}一等奖数据已保存: 期号{prize_data['period']}, 中奖{prize_data['winners']}注, 总奖金{prize_data['total_amount']}元")
                return 1
            except Exception as e:
                logger.error(f"{prize_data['lottery_type']}一等奖数据保存失败: {e}")
                return 0
                
        except Exception as e:
            logger.error(f"保存{prize_data['lottery_type']}数据到数据库失败: {e}")
            return 0
            
    def setup_schedules(self):
        """设置所有彩种的定时任务"""
        logger.info("📅 设置彩票定时任务...")
        

        #因极速Api数据存在延迟问题暂时调整定时任务时间，统一获取开奖时间为21:40， 确保更新奖项时间为23:00

        # 福彩3D：每日21:40获取开奖结果，每日23:00更新各奖项中奖情况
        # schedule.every().day.at("21:40").do(self.fetch_lottery_results, "fc3d")
        # schedule.every().day.at("23:00").do(self.update_prize_info, "fc3d")
        # logger.info("✅ 福彩3D: 每日21:40获取开奖，23:00更新奖项")
        
        # # 双色球：周二、周四、周日的21:40获取开奖结果，23:00更新各奖项中奖情况
        # schedule.every().tuesday.at("21:40").do(self.fetch_lottery_results, "ssq")
        # schedule.every().thursday.at("21:40").do(self.fetch_lottery_results, "ssq")
        # schedule.every().sunday.at("21:40").do(self.fetch_lottery_results, "ssq")
        # schedule.every().tuesday.at("23:00").do(self.update_prize_info, "ssq")
        # schedule.every().thursday.at("23:00").do(self.update_prize_info, "ssq")
        # schedule.every().sunday.at("23:00").do(self.update_prize_info, "ssq")
        # logger.info("✅ 双色球: 周二、周四、周日 21:40获取开奖，23:00更新奖项")
        
        # # 快乐8：每日21:40获取开奖结果，每日23:00更新各奖项中奖情况
        # schedule.every().day.at("21:40").do(self.fetch_lottery_results, "kl8")
        # schedule.every().day.at("23:00").do(self.update_prize_info, "kl8")
        # logger.info("✅ 快乐8: 每日21:40获取开奖，23:00更新奖项")
        
        # # 七乐彩：周一、周三、周五的21:40获取开奖结果，23:00更新各奖项中奖情况
        # schedule.every().monday.at("21:40").do(self.fetch_lottery_results, "qlc")
        # schedule.every().wednesday.at("21:40").do(self.fetch_lottery_results, "qlc")
        # schedule.every().friday.at("21:40").do(self.fetch_lottery_results, "qlc")
        # schedule.every().monday.at("23:00").do(self.update_prize_info, "qlc")
        # schedule.every().wednesday.at("23:00").do(self.update_prize_info, "qlc")
        # schedule.every().friday.at("23:00").do(self.update_prize_info, "qlc")
        # logger.info("✅ 七乐彩: 周一、周三、周五 21:40获取开奖，23:00更新奖项")
        
        # # 大乐透：周一、周三、周六的21:40获取开奖结果，23:00更新各奖项中奖情况
        # schedule.every().monday.at("21:40").do(self.fetch_lottery_results, "dlt")
        # schedule.every().wednesday.at("21:40").do(self.fetch_lottery_results, "dlt")
        # schedule.every().saturday.at("21:40").do(self.fetch_lottery_results, "dlt")
        # schedule.every().monday.at("23:00").do(self.update_prize_info, "dlt")
        # schedule.every().wednesday.at("23:00").do(self.update_prize_info, "dlt")
        # schedule.every().saturday.at("23:00").do(self.update_prize_info, "dlt")
        # logger.info("✅ 大乐透: 周一、周三、周六 21:40获取开奖，23:00更新奖项")
        
        # # 排列3：每日21:40获取开奖结果，每日23:00更新各奖项中奖情况
        
        # schedule.every().day.at("21:40").do(self.fetch_lottery_results, "pl3")
        # schedule.every().day.at("23:00").do(self.update_prize_info, "pl3")
        # logger.info("✅ 排列3: 每日21:40获取开奖，23:00更新奖项")
        
        # # 排列5：每日21:40获取开奖结果，每日23:00更新各奖项中奖情况
        # schedule.every().day.at("21:40").do(self.fetch_lottery_results, "pl5")
        # schedule.every().day.at("23:00").do(self.update_prize_info, "pl5")
        # logger.info("✅ 排列5: 每日21:40获取开奖，23:00更新奖项")
        
        # # 七星彩：周二、周五、周日的21:40获取开奖结果，23:00更新各奖项中奖情况
        # schedule.every().tuesday.at("21:40").do(self.fetch_lottery_results, "qxc")
        # schedule.every().friday.at("21:40").do(self.fetch_lottery_results, "qxc")
        # schedule.every().sunday.at("21:40").do(self.fetch_lottery_results, "qxc")
        # schedule.every().tuesday.at("23:00").do(self.update_prize_info, "qxc")
        # schedule.every().friday.at("23:00").do(self.update_prize_info, "qxc")
        # schedule.every().sunday.at("23:00").do(self.update_prize_info, "qxc")
        # logger.info("✅ 七星彩: 周二、周五、周日 21:40获取开奖，23:00更新奖项")
        
        # === 官网一等奖数据抓取定时任务 ===
        logger.info("🏆 设置官网一等奖数据抓取定时任务...")
        
        # 快乐8：每日23:30抓取选十中十中奖情况
        schedule.every().day.at("23:30").do(self.fetch_official_prize_data, "kl8")
        logger.info("✅ 快乐8: 每日23:30抓取选十中十官网数据")
        
        # 双色球：周二、周四、周日的23:30抓取一等奖中奖情况
        schedule.every().tuesday.at("23:30").do(self.fetch_official_prize_data, "ssq")
        schedule.every().thursday.at("23:30").do(self.fetch_official_prize_data, "ssq")
        schedule.every().sunday.at("23:30").do(self.fetch_official_prize_data, "ssq")
        logger.info("✅ 双色球: 周二、周四、周日 23:30抓取一等奖官网数据")
        
        # 大乐透：周一、周三、周五的23:30抓取一等奖中奖情况
        schedule.every().monday.at("23:30").do(self.fetch_official_prize_data, "dlt")
        schedule.every().wednesday.at("23:30").do(self.fetch_official_prize_data, "dlt")
        schedule.every().friday.at("23:30").do(self.fetch_official_prize_data, "dlt")
        logger.info("✅ 大乐透: 周一、周三、周五 23:30抓取一等奖官网数据")
        
        # 七乐彩：周一、周三、周五的23:30抓取一等奖中奖情况
        schedule.every().monday.at("23:30").do(self.fetch_official_prize_data, "qlc")
        schedule.every().wednesday.at("23:30").do(self.fetch_official_prize_data, "qlc")
        schedule.every().friday.at("23:30").do(self.fetch_official_prize_data, "qlc")
        logger.info("✅ 七乐彩: 周一、周三、周五 23:30抓取一等奖官网数据")
        
        # 七星彩：周二、周五、周日的23:30抓取一等奖中奖情况
        schedule.every().tuesday.at("23:30").do(self.fetch_official_prize_data, "qxc")
        schedule.every().friday.at("23:30").do(self.fetch_official_prize_data, "qxc")
        schedule.every().sunday.at("23:30").do(self.fetch_official_prize_data, "qxc")
        logger.info("✅ 七星彩: 周二、周五、周日 23:30抓取一等奖官网数据")
        
        logger.success("📅 所有彩种定时任务（包含官网数据抓取）设置完成！")
        
    def get_next_jobs(self, limit: int = 30) -> List[Dict]:
        """获取接下来要执行的任务（修复版：包含每日任务的完整显示）"""
        jobs = []
        
        # 🔧 新逻辑：不依赖schedule的next_run，而是基于配置计算完整的任务列表
        schedule_config = {
            'fc3d': {'name': '福彩3D', 'active_days': list(range(7)), 'fetch_time': '21:40', 'update_time': '23:00'},
            'ssq': {'name': '双色球', 'active_days': [1, 3, 6], 'fetch_time': '21:40', 'update_time': '23:00', 'official_time': '23:30'},
            'kl8': {'name': '快乐8', 'active_days': list(range(7)), 'fetch_time': '21:40', 'update_time': '23:00', 'official_time': '23:30'},
            'qlc': {'name': '七乐彩', 'active_days': [0, 2, 4], 'fetch_time': '21:40', 'update_time': '23:00', 'official_time': '23:30'},
            'dlt': {'name': '大乐透', 'active_days': [0, 2, 4], 'fetch_time': '21:40', 'update_time': '23:00', 'official_time': '23:30'},
            'pl3': {'name': '排列3', 'active_days': list(range(7)), 'fetch_time': '21:40', 'update_time': '23:00'},
            'pl5': {'name': '排列5', 'active_days': list(range(7)), 'fetch_time': '21:40', 'update_time': '23:00'},
            'qxc': {'name': '七星彩', 'active_days': [1, 4, 6], 'fetch_time': '21:40', 'update_time': '23:00', 'official_time': '23:30'},
        }
        
        # 官网数据抓取任务的特殊配置
        official_schedule_config = {
            'kl8': {'name': '快乐8选十中十', 'active_days': list(range(7)), 'official_time': '23:30'},
            'ssq': {'name': '双色球一等奖', 'active_days': [1, 3, 6], 'official_time': '23:30'},
            'dlt': {'name': '大乐透一等奖', 'active_days': [0, 2, 4], 'official_time': '23:30'},
            'qlc': {'name': '七乐彩一等奖', 'active_days': [0, 2, 4], 'official_time': '23:30'},
            'qxc': {'name': '七星彩一等奖', 'active_days': [1, 4, 6], 'official_time': '23:30'},
        }
        
        now = datetime.now()
        
        # 生成接下来7天的任务
        for days_ahead in range(7):
            target_date = now + timedelta(days=days_ahead)
            weekday = target_date.weekday()
            
            for lottery_type, config in schedule_config.items():
                if weekday in config['active_days']:
                    # 获取开奖结果任务
                    fetch_time = datetime.combine(target_date.date(), 
                                                datetime.strptime(config['fetch_time'], '%H:%M').time())
                    
                    # 如果是今天，只显示还没执行的任务
                    if days_ahead == 0 and fetch_time <= now:
                        pass  # 跳过已过时间的任务
                    else:
                        jobs.append({
                            'lottery_type': lottery_type,
                            'lottery_name': config['name'],
                            'action': '获取开奖结果',
                            'next_run': fetch_time,
                            'time_until': fetch_time - now
                        })
                    
                    # 更新奖项信息任务
                    update_time = datetime.combine(target_date.date(), 
                                                 datetime.strptime(config['update_time'], '%H:%M').time())
                    
                    # 如果是今天，只显示还没执行的任务
                    if days_ahead == 0 and update_time <= now:
                        pass  # 跳过已过时间的任务
                    else:
                        jobs.append({
                            'lottery_type': lottery_type,
                            'lottery_name': config['name'],
                            'action': '更新奖项信息',
                            'next_run': update_time,
                            'time_until': update_time - now
                        })
                    
                    # 官网一等奖数据抓取任务（如果有配置）
                    if 'official_time' in config:
                        official_time = datetime.combine(target_date.date(), 
                        datetime.strptime(config['official_time'], '%H:%M').time())
                        
                        # 如果是今天，只显示还没执行的任务
                        if days_ahead == 0 and official_time <= now:
                            pass  # 跳过已过时间的任务
                        else:
                            action_name = '抓取官网一等奖数据'
                            if lottery_type == 'kl8':
                                action_name = '抓取官网选十中十数据'
                            
                            jobs.append({
                                'lottery_type': lottery_type,
                                'lottery_name': config['name'],
                                'action': action_name,
                                'next_run': official_time,
                                'time_until': official_time - now
                            })
        
        # 按时间排序，然后取前limit个
        jobs.sort(key=lambda x: x['next_run'])
        return jobs[:limit]
        
    def print_schedule_status(self):
        """打印调度状态"""
        # print("\n" + "="*80)
        # print("🕐 彩票定时任务调度状态")
        # print("="*80)


        logger.info("\n" + "="*80)
        logger.info("🕐 彩票定时任务调度状态")
        logger.info("="*80)

        
        next_jobs = self.get_next_jobs(15)  # 增加显示数量以包含官网抓取任务
        if next_jobs:
            # print(f"📋 接下来 {len(next_jobs)} 个任务:")
            logger.info(f"📋 接下来 {len(next_jobs)} 个任务:")
            for i, job in enumerate(next_jobs, 1):
                time_until = job['time_until']
                if time_until.total_seconds() > 0:
                    days = time_until.days
                    hours, remainder = divmod(time_until.seconds, 3600)
                    minutes, _ = divmod(remainder, 60)
                    
                    time_str = ""
                    if days > 0:
                        time_str += f"{days}天"
                    if hours > 0:
                        time_str += f"{hours}小时"
                    if minutes > 0:
                        time_str += f"{minutes}分钟"
                    if not time_str:
                        time_str = "即将执行"
                    
                    # print(f"  {i:2d}. {job['lottery_name']} - {job['action']}")
                    # print(f"      ⏰ {job['next_run'].strftime('%Y-%m-%d %H:%M:%S')} ({time_str}后)")
                    # print()

                    logger.info(f"  {i:2d}. {job['lottery_name']} - {job['action']}")
                    logger.info(f"      ⏰ {job['next_run'].strftime('%Y-%m-%d %H:%M:%S')} ({time_str}后)")
                    # logger.info()

        else:
            # print("📋 暂无待执行任务")
            logger.info("📋 暂无待执行任务")
            
        # print("="*80)
        logger.info("="*80)
        
    def run_scheduler(self):
        """运行调度器"""
        logger.info("🚀 彩票定时任务调度器启动")
        
        # 设置定时任务
        self.setup_schedules()
        
        # 显示初始状态
        self.print_schedule_status()
        
        logger.info("⏰ 调度器开始运行，等待任务执行...")
        
        try:
            while self.running:
                # 检查并执行待运行的任务
                schedule.run_pending()
                
                # 每10秒检查一次
                time.sleep(10)
                
        except KeyboardInterrupt:
            logger.info("📝 接收到中断信号，正在停止调度器...")
        finally:
            logger.info("⏹️ 彩票定时任务调度器已停止")
            
    def run_manual_task(self, lottery_type: str, action: str):
        """手动执行任务"""
        if action == "fetch":
            logger.info(f"🔧 手动执行: 获取 {lottery_type} 开奖结果")
            self.fetch_lottery_results(lottery_type)
        elif action == "update":
            logger.info(f"🔧 手动执行: 更新 {lottery_type} 奖项信息")
            self.update_prize_info(lottery_type)
        elif action == "official":
            logger.info(f"🔧 手动执行: 抓取 {lottery_type} 官网一等奖数据")
            self.fetch_official_prize_data(lottery_type)
        else:
            logger.error(f"❌ 不支持的操作: {action}")
            logger.info("支持的操作: fetch(获取开奖), update(更新奖项), official(抓取官网数据)")

def main():
    """主函数"""
    import argparse
    
    parser = argparse.ArgumentParser(description="彩票定时任务调度器")
    parser.add_argument("--mode", choices=["daemon", "manual", "status"], default="daemon",
                       help="运行模式: daemon(守护进程), manual(手动执行), status(查看状态)")
    parser.add_argument("--lottery", help="彩票类型 (manual模式必需)")
    parser.add_argument("--action", choices=["fetch", "update", "official"], help="操作类型 (manual模式必需): fetch=获取开奖, update=更新奖项, official=抓取官网数据")
    
    args = parser.parse_args()
    
    scheduler = LotteryScheduler()
    
    if args.mode == "daemon":
        # 守护进程模式
        scheduler.run_scheduler()
    elif args.mode == "manual":
        # 手动执行模式
        if not args.lottery or not args.action:
            print("❌ manual模式需要指定 --lottery 和 --action 参数")
            sys.exit(1)
        scheduler.run_manual_task(args.lottery, args.action)
    elif args.mode == "status":
        # 状态查看模式
        scheduler.setup_schedules()
        scheduler.print_schedule_status()

if __name__ == "__main__":
    main()
